package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exception.LyException;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.Category;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private SpuDetailService spuDetailService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer currentPage, Integer pageSize,Boolean saleable, Long categoryId, Long brandId, Long id) {

        // 1.健壮性
        currentPage = Math.max(currentPage,1);
        pageSize = Math.max(pageSize,5);

        IPage<Spu> iPage = new Page<>(currentPage,pageSize);

        iPage = this.query()
                .eq(saleable != null, "saleable", saleable)
                .eq(categoryId != null, "cid3", categoryId)
                .eq(brandId != null, "brand_id", brandId)
                .eq(id != null, "id", id)
                .page(iPage);

        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(iPage.getRecords());

        spuDTOS.forEach(spuDTO -> {
//            brandService.query().eq("brand_id", spuDTO.getBrandId()).getEntity().getName()
            spuDTO.setBrandName(this.brandService.getById(spuDTO.getBrandId()).getName());
            String name = this.categoryService.listByIds(spuDTO.getCategoryIds())
                    .stream()
                    .map(Category::getName)
                    .collect(Collectors.joining("/"));
            spuDTO.setCategoryName(name);

            spuDTO.setSkus(skuService.querySkuBySpuId(spuDTO.getId()));

            spuDTO.setSpuDetail(spuDetailService.querySpuDetailById(spuDTO.getId()));
        });

        return new PageDTO<>(iPage.getTotal(),iPage.getPages(),spuDTOS);

    }

    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {

        // 新增tb_spu
        Spu spu = spuDTO.toEntity(Spu.class);

        spu.setSaleable(false); // 设置默认下架

        boolean spuSuccess = this.save(spu);

        if (!spuSuccess) {
            throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"新增商品失败");
        }

        // 新增tb_spu_detail
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);

        spuDetail.setSpuId(spu.getId());

        boolean detSuccess = spuDetailService.save(spuDetail);

        if (!detSuccess) {
            throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"新增商品详情失败");
        }

        // 新增sku
        List<Sku> skus = spuDTO.getSkus()
                .stream().map(skuDTO -> {
                    Sku sku = skuDTO.toEntity(Sku.class);
                    sku.setSaleable(false); // 设置默认下架
                    sku.setSpuId(spu.getId());
                    return sku;
        }).collect(Collectors.toList());

        skuService.saveBatch(skus);

//        List<Sku> skuList = spuDTO.getSkus().stream().map(skuDTO -> skuDTO.toEntity(Sku.class)).collect(Collectors.toList());
//
//        for (Sku sku : skuList) {
//            sku.setSaleable(false);
//            sku.setSpuId(spu.getId());
//        }
//
//        skuService.saveBatch(skuList);

    }

    @Override
    @Transactional
    public void updateSpuSaleable(Long id, Boolean saleable) {

        // 更新 SPU
        Spu spu = new Spu();

        spu.setId(id);

        spu.setSaleable(saleable);

        // update tb_spu set saleable = #{saleable} where id = #{id}
        boolean updateSpu = this.updateById(spu);

        if (!updateSpu) {
            throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"更新商品公共表spu失败！");
        }

        //Sku sku = new Sku();

        //sku.setSpuId(spu.getId());

        // 更新SKU
        boolean updateSku = skuService.update().eq("spu_id", id).set("saleable", saleable).update();

        // 多加了一个限定条件，效率更高
        // update tb_sku set saleable = #{saleable} where spu_id = #{id} and saleable = !#{saleable};
        //skuService.update(sku,new QueryWrapper<Sku>().eq("spu_id",id).eq("saleable",!saleable));

        if (!updateSku) {

            throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"更新商品详细表sku失败！");

        }

        // saleable为true时表示上架，为false时表示下架
        String routingKey = saleable ? MQConstants.RoutingKeyConstants.ITEM_UP_KEY : MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;

        this.amqpTemplate.convertAndSend(MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME,routingKey,spu.getId());

    }

    @Override
    public SpuDTO queryGoodsById(Long id) {

        // 1.查询Spu，并将值设置到 SpuDTO 中
        Spu spu = this.getById(id);

        if (spu == null) {

            throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"商品id不存在！");

        }

        SpuDTO spuDTO = new SpuDTO(spu);

        // 2.查询SpuDetail，并将值设置到 SpuDTO 中
        SpuDetail spuDetail = spuDetailService.getById(id);

        if (spuDetail == null) {

            throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"商品id不存在");

        }

        spuDTO.setSpuDetail(new SpuDetailDTO(spuDetail));

        // 3.查询Sku的集合集，并将值设置到 SpuDTO 中
        List<Sku> skus = skuService.query().eq("spu_id", id).list();

        if (CollectionUtils.isEmpty(skus)) {

            throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"商品id不存在");

        }

        spuDTO.setSkus(SkuDTO.convertEntityList(skus));

        return spuDTO;
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {

        // 1.修改 spu
        Long id = spuDTO.getId();
        if (id != null) {

            boolean updateSpu = this.updateById(spuDTO.toEntity(Spu.class));

            if (!updateSpu) {

                throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"更新商品失败！");

            }

        }

        // 2.修改 spuDetail
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();

        if (spuDetailDTO !=null && spuDetailDTO.getSpuId() != null) {

            SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);

            boolean updateSpuDetail = spuDetailService.updateById(spuDetail);

            if (!updateSpuDetail) {

                throw new LyException(HttpStatus.INTERNAL_SERVER_ERROR.value(),"更新商品失败！");

            }

        }

        // 3.修改 sku
        List<SkuDTO> skus = spuDTO.getSkus();

        // 3.1.判断是否包含sku
        if (CollectionUtils.isEmpty(skus)) {

            return;

        }

        // 3.2.转换DTO，并将sku根据saleable是否为null来分组。null，是新增或修改，不是null是删除
        Map<Boolean, List<Sku>> map = skus
                .stream()
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));

        // 3.3 获取新增或修改的sku
        List<Sku> skus1 = map.get(true);

        if (!CollectionUtils.isEmpty(skus1)) {

            skuService.saveOrUpdateBatch(skus1);

        }

        // 3.4 获取删除的sku
        List<Sku> skus2 = map.get(false);

        if (!CollectionUtils.isEmpty(skus2)) {

            List<Long> skuIds = skus2.stream().map(Sku::getId).collect(Collectors.toList());

            skuService.removeByIds(skuIds);

        }

    }

    @Override
    public SpuDTO querySpuById(Long id) {

        return new SpuDTO(this.getById(id));

    }
}
